package com.ecoolex.hotel.saas.core.manager;

import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.StringUtil;
import com.ecoolex.hotel.saas.core.dao.StoreDAO;
import com.ecoolex.hotel.saas.entity.Store;
import com.ecoolex.hotel.saas.entity.Store.Column;
import com.ecoolex.hotel.saas.entity.StoreExample;
import com.ecoolex.hotel.saas.entity.StoreExample.Criteria;
import com.ecoolex.hotel.saas.enums.StoreEnterpriseCertType;
import com.ecoolex.hotel.saas.enums.StoreStatus;
import com.ecoolex.hotel.saas.pojo.EditStoreOneStepDTO;
import com.ecoolex.hotel.saas.pojo.EditStoreStep;
import com.ecoolex.hotel.saas.pojo.EditStoreThreeStepDTO;
import com.ecoolex.hotel.saas.pojo.EditStoreTwoStepDTO;
import com.ecoolex.hotel.saas.pojo.QueryStoreDTO;
import com.ecoolex.hotel.saas.pojo.StoreLicense;

import java.time.Instant;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StoreManager {
	
    @Autowired
    private StoreDAO dao;
    
    @Autowired
    private StoreBrandManager storeBrandManager;
    
    public Long countByBrandId(Integer brandId) {
    	StoreExample example = new StoreExample();
    	Criteria criteria = example.createCriteria();
    	criteria.andBrandIdEqualTo(brandId).andDeletedEqualTo(Store.NOT_DELETED);
    	return dao.countByExample(example);
    }
    
    public Pagination<Store> queryStore(QueryStoreDTO query, StoreLicense license, Page page) {
    	StoreExample example = new StoreExample();
    	Criteria criteria = example.createCriteria();
    	if(Check.notNullOrEmpty(query.getStoreName())) {
    		criteria.andNameLike("%"+query.getStoreName()+"%");
    	}
    	if(Check.notNullAndGtZero(query.getBrandId())) {
    		criteria.andBrandIdEqualTo(query.getBrandId());
    	}
    	if(Check.notNullOrEmpty(query.getStatus())) {
    		criteria.andStatusIn(query.getStatus());
    	}
    	if(Check.notNull(license)) {
    		if(Check.notNullOrEmpty(license.getBrandIdList())) {
    			criteria.andBrandIdIn(license.getBrandIdList());
    		}
    		if(Check.notNullOrEmpty(license.getStoreIdList())) {
    			criteria.andStoreIdIn(license.getStoreIdList());
    		}
    	}
    	criteria.andDeletedEqualTo(Store.NOT_DELETED);
    	example.setOffset(page.getFirstIndex());
    	example.setRows(page.getPageSize());
    	example.orderBy(Column.createTime.desc());
		return Pagination.create(page, 
			dao.countByExample(example),
			() -> dao.selectByExample(example));
	}

    @Cacheable(cacheNames = { "hotel-saas:Store" }, key = "#storeId")
	public Store getStore(Integer storeId) {
		return dao.selectByPrimaryKeyWithLogicalDelete(storeId, Store.NOT_DELETED);
	}

    @Transactional
	@CacheEvict(cacheNames = "hotel-saas:Store",
		key = "#step.storeId",
		condition = "#step.storeId != null",
		beforeInvocation = true)
	public Store updateStoreStep(EditStoreStep step, String updateUser){
		if (step instanceof EditStoreOneStepDTO) {
			return editOne((EditStoreOneStepDTO) step, updateUser);
		} else if (step instanceof EditStoreTwoStepDTO) {
			return editTwo((EditStoreTwoStepDTO) step, updateUser);
		} else {
			return editThree((EditStoreThreeStepDTO) step, updateUser);
		}
	}
    
    private Store editOne(EditStoreOneStepDTO edit, String updateUser) {
    	BizAssert.isTrue(Check.notNull(edit.getBrandId())
			&& Check.notNull(storeBrandManager.get(edit.getBrandId())), ResultCode.BIZ.build(1), "品牌不存在");
		BizAssert.isTrue(StringUtil.isIncludeTrimLength(edit.getName(), 1, 100),
			ResultCode.BIZ.build(2),
			"商户名称只允许1-100个字符");
		Store store = null;
		if(Check.notNullAndGtZero(edit.getStoreId())) {
			store = getStore(edit.getStoreId());
			// TODO 检查是否在关联了优惠券的情况下改变品牌
			// 如果商户状态上线,并且绑定了优惠券, 是不允许更新品牌的
//			if (Check.eq(store.getStatus(), StoreStatus.ONLINE.real())
//				&& couponClassStoreManager.countByStoreId(edit.getStoreId()) > 0) {
//				BizAssert.isTrue(Check.eq(store.getBrandId(), edit.getBrandId()),
//					ResultCode.BIZ.build(12),
//					"商户在绑定了优惠券,无法更新品牌信息");
//			}
			BeanUtil.copy(edit, store);
			store.setUpdateUser(updateUser);
			store.setUpdateTime(Date.from(Instant.now()));
			dao.updateByPrimaryKeySelective(store,
				Column.brandId,
				Column.name,
				Column.logo,
				Column.address,
				Column.contactsName,
				Column.contactsPhone,
				Column.contactsEmail,
				Column.tel,
				Column.serviceQrCode,
				Column.updateUser,
				Column.updateTime);
		}else {
			// 新增
			store = BeanUtil.copy(edit, new Store());
			store.setStatus(StoreStatus.EDITING.real());
			store.setDeleted(Store.NOT_DELETED);
			store.setCreateUser(updateUser);
			store.setCreateTime(Date.from(Instant.now()));
			store.setUpdateUser(updateUser);
			store.setUpdateTime(Date.from(Instant.now()));
			dao.insert(store);
		}
    	return checkEdited(store);
    }
    
    private Store editTwo(EditStoreTwoStepDTO edit, String updateUser) {
    	//企业证件类型为营业执照时，以下参数必填
    	if(Check.eq(edit.getIdentityType(), StoreEnterpriseCertType.BUSINESS_LICENSE)) {
    		BizAssert.isTrue(Check.notNullOrEmpty(edit.getTaxRegistrationNo()),ResultCode.BIZ.build(1), "税务登记编号不能为空");
    		BizAssert.isTrue(Check.notNullOrEmpty(edit.getOrganizationCode()),ResultCode.BIZ.build(2), "组织机构代码证编号不能为空");
    		BizAssert.isTrue(Check.notNull(edit.getOrganizationCodeValidity()),ResultCode.BIZ.build(3), "组织机构代码证有效期不能为空");
    		BizAssert.isTrue(Check.notNullOrEmpty(edit.getOrganizationCodeImg()),ResultCode.BIZ.build(4), "组织机构代码证不能为空");
    		BizAssert.isTrue(Check.notNullOrEmpty(edit.getTaxRegistration()),ResultCode.BIZ.build(5), "税务登记不能为空");
    	}
    	Store store = getStore(edit.getStoreId());
    	store = BeanUtil.copy(edit, store);
		store.setUpdateUser(updateUser);
		store.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(store,
			Column.businessLicense,
			Column.businessLicenseName,
			Column.collectionShorter,
			Column.enterpriseCertType,
			Column.enterpriseCertNo,
			Column.legalPersonName,
			Column.businessLicenseDate,
			Column.registerCityId,
			Column.registerAddress,
			Column.taxRegistrationNo,
			Column.organizationCode,
			Column.organizationCodeValidity,
			Column.organizationCodeImg,
			Column.taxRegistration,
			Column.identityFrontImage,
			Column.identityBackImage,
			Column.identityType,
			Column.identityNo,
			Column.identityValidityStartTime,
			Column.updateUser,
			Column.updateTime);
    	return checkEdited(store);
    }

    private Store editThree(EditStoreThreeStepDTO edit, String updateUser) {
    	Store store = getStore(edit.getStoreId());
    	store = BeanUtil.copy(edit, store);
		store.setUpdateUser(updateUser);
		store.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(store,
			Column.settleAccountName,
			Column.bankAccount,
			Column.accountProvince,
			Column.accountCity,
			Column.bankName,
			Column.bankBranchName,
			Column.bankUnionPayNo,
			Column.updateUser,
			Column.updateTime);
    	return checkEdited(store);
    }
    
    private Store checkEdited(Store store) {
		if (Check.notEq(store.getStatus(), StoreStatus.EDITING.real())) {
			return store;
		}
		if (Check.isNull(store.getBrandId())) {
			return store;
		}else if(Check.isNull(store.getBusinessLicense())) {
			return store;
		}else if(Check.isNull(store.getSettleAccountName())) {
			return store;
		}
		store.setStatus(StoreStatus.EDITED.real());
		dao.updateByPrimaryKeySelective(store, Column.status);
		return store;
	}

	@Transactional
	@CacheEvict(cacheNames = "hotel-saas:Store", key = "#record.storeId")
	public Boolean delStore(Store record, String updateUser){
		BizAssert.isTrue(Check.notEq(record.getStatus(), StoreStatus.ONLINE.real()),
			ResultCode.BIZ.build(1),
			"删除商户必须非上线状态");
		// TODO 删除所有与此商户关联的优惠券
		
		record.setDeleted(Store.IS_DELETED);
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(record, Column.deleted,Column.updateUser,Column.updateTime);
		return true;
	}

	@CacheEvict(cacheNames = "hotel-saas:Store", key = "#store.storeId")
	public Store onlineStore(Store store, String updateUser){
		BizAssert.isTrue(Check.eq(store.getStatus(), StoreStatus.EDITED.real()),
			ResultCode.BIZ.build(1),
			"上线必须是编辑完成状态");
		store.setStatus(StoreStatus.ONLINE.real());
		store.setUpdateUser(updateUser);
		store.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(store, Column.status,Column.updateUser,Column.updateTime);
		return store;
	}
	
	@CacheEvict(cacheNames = "hotel-saas:Store", key = "#store.storeId")
	public Store offlineStore(Store store, String updateUser){
		BizAssert.isTrue(Check.eq(store.getStatus(), StoreStatus.ONLINE.real()), ResultCode.BIZ.build(1), "下线必须是上线状态");
		// TODO 检查是否关联了优惠券
//		BizAssert.isTrue(couponClassStoreManager.countByStoreId(store.getStoreId()) < 1,
//			ResultCode.BIZ.build(2),
//			"关联了优惠券无法下线");
		store.setStatus(StoreStatus.EDITED.real());
		store.setUpdateUser(updateUser);
		store.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(store, Column.status,Column.updateUser,Column.updateTime);
		return store;
	}
}